package com.backwaveweibo.bww.service.impl;

import com.backwaveweibo.bww.service.ElasticsearchService;
import com.backwaveweibo.bww.utils.Result;
import com.backwaveweibo.bww.utils.ResultCode;
import com.backwaveweibo.bww.utils.ResultGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Map;

/**
 * @author GHW : RD-Kelsey
 * @description ES-搜索引擎-业务实现类
 * @date 2020/6/16
 */

@Service
@Slf4j
public class ElasticsearchServiceImpl<T> implements ElasticsearchService<T> {

    //ES客户端
    @Resource
    private RestHighLevelClient client;

    /**
     * 同步到ES
     *
     * @param docId     文档的id，必须是String类型，建议使用实体的自增长id，如果不传，会自动生成，但不方便获取。
     * @param data      要传的对象，方法会自动转成JSON，注意实体中对字段用注解进行标注。
     * @param indexName 索引名字，相当于表名，如果ES中没有对应的索引会自动创建，有就直接在该索引下插入数据
     * @return true | false
     */
    @Override
    public boolean importToES(@RequestParam String docId, T data, String indexName) throws IOException {
        //自动将数据转成JSON
        String jsonResult = new ObjectMapper().writeValueAsString(data);
        //开启一个请求
        IndexRequest indexRequest = new IndexRequest(indexName);
        //文档id
        indexRequest.id(docId);
        //要存入的数据，指定格式
        indexRequest.source(jsonResult, XContentType.JSON);
        //开始存入
        IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
        //获取存入状态
        return indexResponse.status() == RestStatus.CREATED;
    }

    /**
     * 从ES中删除文档
     *
     * @param indexName 索引名称
     * @param docId     文档id
     * @return true | false
     */
    @Override
    public boolean deleteFromES(String indexName, String docId) {
        DeleteRequest deleteRequest = new DeleteRequest(indexName, docId);
        try {
            DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
            return deleteResponse.status() == RestStatus.OK;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据id获取微博
     *
     * @param docId 文档id
     * @return ES响应结果
     * @throws IOException IO
     */
    public Result getById(String docId) throws IOException {
        GetRequest getRequest = new GetRequest("weibo");
        getRequest.id(docId);

        Map<String, Object> source = client.get(getRequest, RequestOptions.DEFAULT).getSource();
        log.info("搜索结果==>{}", source);
        return ResultGenerator.genSuccessResult(ResultCode.SUCCESS, "成功", source);
    }


    /**
     * 根据 关键词 搜索
     *
     * @param content
     * @return
     * @throws IOException
     */
    @Override
    public SearchHit[] getByContent(String content) throws IOException {
        SearchRequest searchRequest = new SearchRequest("weibo");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        SearchSourceBuilder query = searchSourceBuilder
                .query(QueryBuilders
                        .boolQuery()
                        .should(QueryBuilders
                                .matchQuery("content", content)));
        SearchResponse searchResponse = client.search(searchRequest.source(query), RequestOptions.DEFAULT);
        return searchResponse.getHits().getHits();
    }
}
